Skip to content

Conversation

@LauraBeatris
Copy link
Member

@LauraBeatris LauraBeatris commented Nov 5, 2025

Description

This PR allows developers to enable the organization's featureset in-app instead of having to go to the Clerk Dashboard, decreasing friction to build B2B apps.

The prompt only appears for development instances only.

CleanShot 2025-11-21 at 10 36 36

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • New Features

    • In-app development prompt to enable Organizations when org features are first used in dev — lazy-loadable, themed, with success state, dashboard link, and optional personal-accounts toggle.
    • Organization hooks/components now trigger the enablement flow automatically in development.
  • Chores

    • Minor bundle size adjustments to include prompt assets.
  • Accessibility

    • Modal initial-focus control added for improved keyboard focus.

✏️ Tip: You can customize this high-level summary in your review settings.

@LauraBeatris LauraBeatris self-assigned this Nov 5, 2025
@changeset-bot
Copy link

changeset-bot bot commented Nov 5, 2025

🦋 Changeset detected

Latest commit: 6f4897e

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 22 packages
Name Type
@clerk/clerk-js Minor
@clerk/shared Minor
@clerk/clerk-react Minor
@clerk/vue Minor
@clerk/chrome-extension Patch
@clerk/clerk-expo Patch
@clerk/agent-toolkit Patch
@clerk/astro Patch
@clerk/backend Patch
@clerk/elements Patch
@clerk/expo-passkeys Patch
@clerk/express Patch
@clerk/fastify Patch
@clerk/nextjs Patch
@clerk/nuxt Patch
@clerk/react-router Patch
@clerk/remix Patch
@clerk/tanstack-react-start Patch
@clerk/testing Patch
@clerk/themes Patch
@clerk/types Patch
@clerk/localizations Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel
Copy link

vercel bot commented Nov 5, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
clerk-js-sandbox Ready Ready Preview Comment Nov 21, 2025 4:16pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 5, 2025

Walkthrough

Adds an in-app development prompt and internal APIs to enable the Organizations feature from the app; introduces a DevTools endpoint, new UI components/providers/hooks, SSR premount plumbing, type and appearance additions, lazy-module wiring, and replaces scattered org-flag checks with a centralized enablement flow.

Changes

Cohort / File(s) Summary
Bundle config
packages/clerk-js/bundlewatch.config.json
Updated bundle size thresholds and added enableOrganizationsPrompt*.js entries.
Core Clerk + DevTools
packages/clerk-js/src/core/clerk.ts, packages/clerk-js/src/core/resources/DevTools.ts
Added Clerk internals: __internal_attemptToEnableEnvironmentSetting, __internal_openEnableOrganizationsPrompt, __internal_closeEnableOrganizationsPrompt; DevTools resource exposes __internal_enableEnvironmentSetting PATCH.
Shared types & devtools
packages/shared/src/types/clerk.ts, packages/shared/src/types/devtools.ts, packages/shared/src/types/index.ts, packages/shared/src/types/appearance.ts
Added internal prompt/attempt types and result types; EnableEnvironmentSettingParams, DevToolsResource; exported devtools types; added EnableOrganizationsTheme and enableOrganizations appearance field.
UI components & state
packages/clerk-js/src/ui/Components.tsx, packages/clerk-js/src/ui/elements/Modal.tsx, packages/clerk-js/src/ui/elements/contexts/index.tsx, packages/clerk-js/src/ui/customizables/parseAppearance.ts
Wired modal/state for enableOrganizationsPrompt, added initialFocusRef prop to Modal, added flow/appearance keys for enableOrganizations prompt.
Enable organizations prompt UI
packages/clerk-js/src/ui/components/devPrompts/EnableOrganizationsPrompt/index.tsx
New React component implementing the enable flow (UI, loading, optional personal-accounts toggle, DevTools call, success handling and reload).
Dev prompt shared & Keyless refactor
packages/clerk-js/src/ui/components/devPrompts/shared.tsx, packages/clerk-js/src/ui/components/devPrompts/KeylessPrompt/index.tsx, packages/clerk-js/src/ui/components/devPrompts/KeylessPrompt/use-revalidate-environment.ts
Added PromptContainer, base prompt styles, icons, URL parsing utility; refactored KeylessPrompt to use shared utilities; fixed import paths.
Lazy modules & providers
packages/clerk-js/src/ui/lazyModules/components.ts, packages/clerk-js/src/ui/lazyModules/providers.tsx
Added lazy export EnableOrganizationsPrompt and LazyEnableOrganizationsPromptProvider (AppearanceProvider + Suspense).
React isomorphic/hydration
packages/react/src/isomorphicClerk.ts
Added premount queuing and preopenEnableOrganizationsPrompt; added methods to open/close prompt and attempt enablement before ClerkJS hydrates.
Shared hooks & integrations
packages/shared/src/organization.ts, packages/shared/src/react/hooks/useOrganization.tsx, packages/shared/src/react/hooks/useOrganizationList.tsx, packages/vue/src/composables/useOrganization.ts
Added useAttemptToEnableOrganizations hook; invoked from organization hooks/composable to attempt enabling organizations once per mount/use (guarded).
Context migrations
packages/clerk-js/src/ui/components/APIKeys/APIKeys.tsx, packages/shared/src/react/commerce.tsx, packages/shared/src/react/hooks/useCheckout.ts, packages/shared/src/react/__tests__/commerce.test.tsx
Replaced useOrganization usage with useOrganizationContext to avoid triggering the in-app prompt in certain flows; updated logic/tests accordingly.
Removed legacy export
packages/clerk-js/src/ui/components/KeylessPrompt/ClerkLogoIcon.tsx
Removed exported ClerkLogoIcon (moved into shared devPrompts utilities).
Version bump changelog
.changeset/flat-ravens-call.md
Documented minor version bumps for related packages.

Sequence Diagram(s)

sequenceDiagram
    participant Component as Org Component
    participant Clerk as Clerk Core
    participant Modal as EnableOrgsPrompt
    participant DevTools as DevTools API

    Note over Clerk,Modal: Centralized enablement flow

    Component->>Clerk: __internal_attemptToEnableEnvironmentSetting({for: "organizations", caller})
    alt development & not enabled
        Clerk->>Modal: __internal_openEnableOrganizationsPrompt(props)
        Modal->>Developer: render prompt (toggle, enable)
        Developer->>Modal: click Enable
        Modal->>DevTools: __internal_enableEnvironmentSetting(params)
        DevTools-->>Modal: success
        Modal->>Browser: trigger reload / call onSuccess
        Clerk-->>Component: { status: "prompt-shown" }
    else enabled or production
        Clerk-->>Component: { status: "enabled" }
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~35–45 minutes

  • Attention points:
    • EnableOrganizationsPrompt UI accessibility, DevTools call, reload/onSuccess handling.
    • packages/clerk-js/src/core/clerk.ts enablement logic, telemetry and side-effects.
    • packages/react/src/isomorphicClerk.ts premount queuing and hydration edge-cases.
    • Cross-package type additions in packages/shared/src/types/* and usages.

Poem

🐰 I found a prompt beneath the code,

I flipped a coin and watched features grow.
Devs click enable — no dashboard roam,
The app now welcomes organizations home.
Hop, hop — deploy and go!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely describes the main change: introducing a development modal to enable organizations across multiple packages (clerk-js, clerk-react, vue).
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch laura/enable-orgs

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 17978b5 and 6f4897e.

📒 Files selected for processing (1)
  • packages/clerk-js/src/ui/components/devPrompts/EnableOrganizationsPrompt/index.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/clerk-js/src/ui/components/devPrompts/EnableOrganizationsPrompt/index.tsx (7)
packages/shared/src/types/clerk.ts (1)
  • __internal_EnableOrganizationsPromptProps (1449-1459)
packages/shared/src/types/devtools.ts (1)
  • EnableEnvironmentSettingParams (3-6)
packages/clerk-js/src/core/resources/DevTools.ts (1)
  • DevTools (8-21)
packages/clerk-js/src/ui/elements/Modal.tsx (1)
  • Modal (26-111)
packages/clerk-js/src/ui/components/devPrompts/shared.tsx (4)
  • PromptContainer (10-28)
  • basePromptElementStyles (33-55)
  • ClerkLogoIcon (105-176)
  • PromptSuccessIcon (57-82)
packages/clerk-js/src/ui/customizables/index.ts (3)
  • Flex (16-16)
  • Box (15-15)
  • Span (75-75)
packages/clerk-js/src/ui/lazyModules/components.ts (1)
  • EnableOrganizationsPrompt (49-51)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (1)
packages/clerk-js/src/ui/components/devPrompts/EnableOrganizationsPrompt/index.tsx (1)

93-107: Verify intent of tabIndex={-1} on heading.

A past review comment (marked as addressed in commits 7dfbc66 to c38fd6e) suggested removing tabIndex={-1} from this heading, but it's still present in the current code.

While tabIndex={-1} on a non-interactive heading used as initialFocusRef is a common pattern for modal focus management (allows programmatic focus without adding to tab order), the discrepancy between the "addressed" status and the current code suggests either a revert, merge conflict, or deliberate re-addition.

Please confirm whether:

  • This attribute should be removed per the original review comment, or
  • It was deliberately kept/re-added as the correct pattern for modal focus management

Comment @coderabbitai help to get the list of available commands and usage tips.

@clerk-cookie
Copy link
Collaborator

Hey @LauraBeatris - the snapshot version command generated the following package versions:

Package Version
@clerk/agent-toolkit 0.2.4-snapshot.v20251121134419
@clerk/astro 2.16.2-snapshot.v20251121134419
@clerk/backend 2.23.2-snapshot.v20251121134419
@clerk/chrome-extension 2.8.4-snapshot.v20251121134419
@clerk/clerk-js 5.110.0-snapshot.v20251121134419
@clerk/elements 0.23.85-snapshot.v20251121134419
@clerk/clerk-expo 2.19.4-snapshot.v20251121134419
@clerk/expo-passkeys 0.4.21-snapshot.v20251121134419
@clerk/express 1.7.52-snapshot.v20251121134419
@clerk/fastify 2.6.4-snapshot.v20251121134419
@clerk/localizations 3.28.3-snapshot.v20251121134419
@clerk/nextjs 6.35.4-snapshot.v20251121134419
@clerk/nuxt 1.13.2-snapshot.v20251121134419
@clerk/clerk-react 5.57.0-snapshot.v20251121134419
@clerk/react-router 2.2.4-snapshot.v20251121134419
@clerk/remix 4.13.19-snapshot.v20251121134419
@clerk/shared 3.36.0-snapshot.v20251121134419
@clerk/tanstack-react-start 0.27.4-snapshot.v20251121134419
@clerk/testing 1.13.18-snapshot.v20251121134419
@clerk/themes 2.4.39-snapshot.v20251121134419
@clerk/types 4.101.2-snapshot.v20251121134419
@clerk/vue 1.17.0-snapshot.v20251121134419

Tip: Use the snippet copy button below to quickly install the required packages.
@clerk/agent-toolkit

npm i @clerk/agent-toolkit@0.2.4-snapshot.v20251121134419 --save-exact

@clerk/astro

npm i @clerk/astro@2.16.2-snapshot.v20251121134419 --save-exact

@clerk/backend

npm i @clerk/backend@2.23.2-snapshot.v20251121134419 --save-exact

@clerk/chrome-extension

npm i @clerk/chrome-extension@2.8.4-snapshot.v20251121134419 --save-exact

@clerk/clerk-js

npm i @clerk/clerk-js@5.110.0-snapshot.v20251121134419 --save-exact

@clerk/elements

npm i @clerk/elements@0.23.85-snapshot.v20251121134419 --save-exact

@clerk/clerk-expo

npm i @clerk/clerk-expo@2.19.4-snapshot.v20251121134419 --save-exact

@clerk/expo-passkeys

npm i @clerk/expo-passkeys@0.4.21-snapshot.v20251121134419 --save-exact

@clerk/express

npm i @clerk/express@1.7.52-snapshot.v20251121134419 --save-exact

@clerk/fastify

npm i @clerk/fastify@2.6.4-snapshot.v20251121134419 --save-exact

@clerk/localizations

npm i @clerk/localizations@3.28.3-snapshot.v20251121134419 --save-exact

@clerk/nextjs

npm i @clerk/nextjs@6.35.4-snapshot.v20251121134419 --save-exact

@clerk/nuxt

npm i @clerk/nuxt@1.13.2-snapshot.v20251121134419 --save-exact

@clerk/clerk-react

npm i @clerk/clerk-react@5.57.0-snapshot.v20251121134419 --save-exact

@clerk/react-router

npm i @clerk/react-router@2.2.4-snapshot.v20251121134419 --save-exact

@clerk/remix

npm i @clerk/remix@4.13.19-snapshot.v20251121134419 --save-exact

@clerk/shared

npm i @clerk/shared@3.36.0-snapshot.v20251121134419 --save-exact

@clerk/tanstack-react-start

npm i @clerk/tanstack-react-start@0.27.4-snapshot.v20251121134419 --save-exact

@clerk/testing

npm i @clerk/testing@1.13.18-snapshot.v20251121134419 --save-exact

@clerk/themes

npm i @clerk/themes@2.4.39-snapshot.v20251121134419 --save-exact

@clerk/types

npm i @clerk/types@4.101.2-snapshot.v20251121134419 --save-exact

@clerk/vue

npm i @clerk/vue@1.17.0-snapshot.v20251121134419 --save-exact

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (6)
packages/clerk-js/src/core/clerk.ts (2)

788-800: Use eventPrebuiltComponentOpened for prompt telemetry to match other modals

__internal_openEnableOrganizationsPrompt currently records eventPrebuiltComponentMounted('EnableOrganizationsPrompt', props), while other “open modal” methods (openSignIn, openUserProfile, etc.) use eventPrebuiltComponentOpened. For consistency and clearer analytics semantics (“prompt shown” vs “component mounted”), consider:

-    this.telemetry?.record(eventPrebuiltComponentMounted('EnableOrganizationsPrompt', props));
+    this.telemetry?.record(eventPrebuiltComponentOpened('EnableOrganizationsPrompt', props));

This keeps telemetry for the new prompt aligned with existing prebuilt components.


750-785: Avoid unsafe cast and align prompt props caller union with attempt params

__internal_attemptToEnableEnvironmentSetting still needs to coerce the object passed to __internal_openEnableOrganizationsPrompt via as __internal_EnableOrganizationsPromptProps, because caller in __internal_AttemptToEnableEnvironmentSettingParams includes 'CreateOrganization' and 'TaskChooseOrganization' while __internal_EnableOrganizationsPromptProps['caller'] does not.

To keep types honest and avoid this cast:

  • Extend __internal_EnableOrganizationsPromptProps['caller'] to include all values from __internal_AttemptToEnableEnvironmentSettingParams['caller'] (or extract a shared union), then
  • Drop the as __internal_EnableOrganizationsPromptProps assertion and pass the object directly.

This restores exhaustiveness and prevents subtle bugs if the prompt later branches on new caller values.

packages/react/src/isomorphicClerk.ts (1)

1490-1499: Clarify semantics of __internal_attemptToEnableEnvironmentSetting when ClerkJS isn’t loaded

Right now, __internal_attemptToEnableEnvironmentSetting queues a premount callback and returns void when clerkjs is not yet loaded. Callers must therefore defensively handle an undefined result, even though the underlying core method always returns a status.

Given this API is used to gate rendering and decide whether to show the dev prompt, consider instead:

  • Returning an explicit rejected state when ClerkJS is unavailable (e.g. { status: 'rejected' }), or
  • Clearly documenting and typing the void case at call sites so they don’t assume a status is always present.

This avoids silent no‑ops in SSR/early‑mount scenarios where enablement decisions are needed synchronously.

packages/shared/src/types/clerk.ts (1)

323-339: Align caller unions and document rejected status to keep internal types coherent

A couple of type‑surface inconsistencies remain around the new enable‑organizations flow:

  1. Caller unions are still out of sync

    • __internal_EnableOrganizationsPromptProps['caller'] only allows:
      • 'OrganizationSwitcher' | 'OrganizationProfile' | 'OrganizationList' | 'useOrganizationList' | 'useOrganization'.
    • __internal_AttemptToEnableEnvironmentSettingParams['caller'] additionally allows:
      • 'CreateOrganization' | 'TaskChooseOrganization'.

    This mismatch is what forces the cast in Clerk.__internal_attemptToEnableEnvironmentSetting. Recommend extracting a shared type __internal_OrganizationCaller = … and using it in both definitions so all entrypoints are covered and the cast can be removed. (Also see the corresponding call site in packages/clerk-js/src/core/clerk.ts.)

  2. rejected status isn’t described or currently produced

    __internal_AttemptToEnableEnvironmentSettingResult includes a 'rejected' status, but the Clerk implementation currently only returns 'enabled' or 'prompt-shown', and the docblock for __internal_attemptToEnableEnvironmentSetting doesn’t mention 'rejected'.

    Either:

    • Start returning 'rejected' from appropriate callers (e.g. when enablement can’t be attempted), or
    • Remove 'rejected' from the union and adjust the doc comment accordingly.

Keeping these internal types and docs tightly aligned will make this enablement flow easier to evolve safely.

Also applies to: 1449-1476

packages/clerk-js/src/ui/components/devPrompts/EnableOrganizationsPrompt/index.tsx (2)

54-71: Include window.location.href in useMemo dependencies.

The useMemo hook at line 56 reads window.location.href but doesn't list it in the dependency array (line 71). While window.location.href rarely changes in SPAs, including it ensures the memo recomputes correctly if the URL does change.

Apply this diff:

   const organizationsDashboardUrl = useMemo(() => {
     return withLastActiveFallback(() => {
       const currentUrl = window.location.href;
       try {
         const redirectUrlParts = handleDashboardUrlParsing(currentUrl);
         const url = new URL(
           `${redirectUrlParts.baseDomain}/apps/${redirectUrlParts.appId}/instances/${redirectUrlParts.instanceId}/organizations`,
         );
         return url.href;
       } catch {
         if (!environment?.id) {
           throw new Error('Cannot construct dashboard URL');
         }

         return 'https://dashboard.clerk.com/last-active?path=organization-settings';
       }
     });
-  }, [environment?.id]);
+  }, [environment?.id, window.location.href]);

658-681: Add hover and focus-visible styles to Link component.

The Link component lacks hover and focus-visible styles, which affects usability and accessibility. Interactive elements should provide visual feedback on hover and keyboard focus.

Apply this diff:

 const Link = forwardRef<HTMLAnchorElement, React.ComponentProps<'a'> & { css?: SerializedStyles }>(
   ({ children, css: cssProp, ...props }, ref) => {
     return (
       <a
         ref={ref}
         {...props}
         css={[
           basePromptElementStyles,
           css`
             color: #a8a8ff;
             font-size: inherit;
             font-weight: 500;
             line-height: 1.3;
             font-size: 0.8125rem;
             min-width: 0;
+            cursor: pointer;
+            transition: color 120ms ease-in-out;
+            
+            &:hover {
+              color: #c4c4ff;
+            }
+            
+            &:focus-visible {
+              outline: 2px solid white;
+              outline-offset: 2px;
+              border-radius: 2px;
+            }
+            
+            @media (prefers-reduced-motion: reduce) {
+              transition: none;
+            }
           `,
           cssProp,
         ]}
       >
         {children}
       </a>
     );
   },
 );
🧹 Nitpick comments (2)
packages/shared/src/react/hooks/useOrganization.tsx (1)

283-283: LGTM: Hook invocation is well-integrated.

The useAttemptToEnableOrganizations hook is correctly placed after the provider assertion and before organization-related logic. The implementation properly guards against duplicate attempts and handles cases where the enablement API isn't available.

Optional: Consider adding JSDoc documentation.

While the PR objectives note that JSDoc is incomplete, adding a brief comment explaining that this hook triggers the development-mode organizations enablement flow would improve maintainability for future developers.

Example:

 useAssertWrappedByClerkProvider('useOrganization');
+// Attempt to enable organizations in development mode if not already enabled
 useAttemptToEnableOrganizations('useOrganization');
packages/clerk-js/src/ui/components/devPrompts/EnableOrganizationsPrompt/index.tsx (1)

73-93: Consider adding user feedback for enablement failures.

The catch block (lines 90-92) resets isLoading but doesn't provide visual feedback about what went wrong. Users see the button become enabled again without knowing if the request failed or why.

Consider adding an error state and displaying it to users:

 const [isLoading, setIsLoading] = useState(false);
 const [isEnabled, setIsEnabled] = useState(false);
+const [error, setError] = useState<string | null>(null);

 const handleEnableOrganizations = () => {
   setIsLoading(true);
+  setError(null);
   
   const params: EnableEnvironmentSettingParams = {
     enable_organizations: true,
   };
   
   if (hasPersonalAccountsEnabled) {
     params.organization_allow_personal_accounts = allowPersonalAccount;
   }
   
   void new DevTools()
     .__internal_enableEnvironmentSetting(params)
     .then(() => {
       setIsEnabled(true);
       setIsLoading(false);
     })
     .catch(() => {
       setIsLoading(false);
+      setError('Failed to enable Organizations. Please try again or contact support.');
     });
 };

Then display error in the UI below the description text when it's set.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between a7cdb01 and 60e0b72.

📒 Files selected for processing (28)
  • .changeset/flat-ravens-call.md (1 hunks)
  • packages/clerk-js/bundlewatch.config.json (2 hunks)
  • packages/clerk-js/src/core/clerk.ts (9 hunks)
  • packages/clerk-js/src/core/resources/DevTools.ts (1 hunks)
  • packages/clerk-js/src/ui/Components.tsx (11 hunks)
  • packages/clerk-js/src/ui/components/APIKeys/APIKeys.tsx (2 hunks)
  • packages/clerk-js/src/ui/components/KeylessPrompt/ClerkLogoIcon.tsx (0 hunks)
  • packages/clerk-js/src/ui/components/devPrompts/EnableOrganizationsPrompt/index.tsx (1 hunks)
  • packages/clerk-js/src/ui/components/devPrompts/KeylessPrompt/index.tsx (9 hunks)
  • packages/clerk-js/src/ui/components/devPrompts/KeylessPrompt/use-revalidate-environment.ts (1 hunks)
  • packages/clerk-js/src/ui/components/devPrompts/shared.tsx (1 hunks)
  • packages/clerk-js/src/ui/customizables/parseAppearance.ts (1 hunks)
  • packages/clerk-js/src/ui/elements/Modal.tsx (2 hunks)
  • packages/clerk-js/src/ui/elements/contexts/index.tsx (1 hunks)
  • packages/clerk-js/src/ui/lazyModules/components.ts (4 hunks)
  • packages/clerk-js/src/ui/lazyModules/providers.tsx (1 hunks)
  • packages/react/src/isomorphicClerk.ts (5 hunks)
  • packages/shared/src/organization.ts (2 hunks)
  • packages/shared/src/react/__tests__/commerce.test.tsx (1 hunks)
  • packages/shared/src/react/commerce.tsx (2 hunks)
  • packages/shared/src/react/hooks/useCheckout.ts (3 hunks)
  • packages/shared/src/react/hooks/useOrganization.tsx (2 hunks)
  • packages/shared/src/react/hooks/useOrganizationList.tsx (2 hunks)
  • packages/shared/src/types/appearance.ts (2 hunks)
  • packages/shared/src/types/clerk.ts (2 hunks)
  • packages/shared/src/types/devtools.ts (1 hunks)
  • packages/shared/src/types/index.ts (1 hunks)
  • packages/vue/src/composables/useOrganization.ts (2 hunks)
💤 Files with no reviewable changes (1)
  • packages/clerk-js/src/ui/components/KeylessPrompt/ClerkLogoIcon.tsx
🚧 Files skipped from review as they are similar to previous changes (11)
  • packages/shared/src/react/commerce.tsx
  • packages/shared/src/react/hooks/useOrganizationList.tsx
  • packages/clerk-js/src/ui/components/devPrompts/KeylessPrompt/use-revalidate-environment.ts
  • packages/clerk-js/src/core/resources/DevTools.ts
  • .changeset/flat-ravens-call.md
  • packages/clerk-js/src/ui/components/devPrompts/shared.tsx
  • packages/shared/src/types/devtools.ts
  • packages/shared/src/organization.ts
  • packages/clerk-js/src/ui/elements/contexts/index.tsx
  • packages/shared/src/react/hooks/useCheckout.ts
  • packages/vue/src/composables/useOrganization.ts
🧰 Additional context used
🧬 Code graph analysis (9)
packages/clerk-js/src/ui/elements/Modal.tsx (2)
packages/clerk-js/src/ui/elements/contexts/index.tsx (1)
  • withFloatingTree (140-155)
packages/clerk-js/src/ui/hooks/useScrollLock.ts (1)
  • useScrollLock (69-85)
packages/clerk-js/src/ui/components/devPrompts/KeylessPrompt/index.tsx (1)
packages/clerk-js/src/ui/components/devPrompts/shared.tsx (3)
  • basePromptElementStyles (33-55)
  • PromptContainer (10-28)
  • PromptSuccessIcon (57-82)
packages/clerk-js/src/ui/lazyModules/components.ts (1)
packages/clerk-js/src/ui/components/devPrompts/EnableOrganizationsPrompt/index.tsx (1)
  • EnableOrganizationsPrompt (433-439)
packages/clerk-js/src/ui/components/devPrompts/EnableOrganizationsPrompt/index.tsx (5)
packages/shared/src/types/clerk.ts (1)
  • __internal_EnableOrganizationsPromptProps (1449-1459)
packages/clerk-js/src/ui/components/devPrompts/shared.tsx (5)
  • handleDashboardUrlParsing (84-100)
  • PromptContainer (10-28)
  • PromptSuccessIcon (57-82)
  • ClerkLogoIcon (105-176)
  • basePromptElementStyles (33-55)
packages/shared/src/types/devtools.ts (1)
  • EnableEnvironmentSettingParams (3-6)
packages/clerk-js/src/core/resources/DevTools.ts (1)
  • DevTools (8-21)
packages/clerk-js/src/ui/elements/Modal.tsx (1)
  • Modal (26-111)
packages/shared/src/react/hooks/useOrganization.tsx (1)
packages/shared/src/organization.ts (1)
  • useAttemptToEnableOrganizations (27-43)
packages/react/src/isomorphicClerk.ts (1)
packages/shared/src/types/clerk.ts (3)
  • __internal_EnableOrganizationsPromptProps (1449-1459)
  • __internal_AttemptToEnableEnvironmentSettingParams (1461-1472)
  • __internal_AttemptToEnableEnvironmentSettingResult (1474-1476)
packages/clerk-js/src/core/clerk.ts (3)
packages/shared/src/types/clerk.ts (2)
  • __internal_AttemptToEnableEnvironmentSettingParams (1461-1472)
  • __internal_EnableOrganizationsPromptProps (1449-1459)
packages/clerk-js/src/utils/componentGuards.ts (1)
  • disabledOrganizationsFeature (21-23)
packages/shared/src/telemetry/events/component-mounted.ts (1)
  • eventPrebuiltComponentMounted (69-75)
packages/clerk-js/src/ui/lazyModules/providers.tsx (3)
packages/shared/src/types/appearance.ts (1)
  • Appearance (1057-1131)
packages/clerk-js/src/ui/router/VirtualRouter.tsx (1)
  • VirtualRouter (15-67)
packages/clerk-js/src/ui/customizables/index.ts (1)
  • AppearanceProvider (9-9)
packages/clerk-js/src/ui/Components.tsx (4)
packages/shared/src/types/clerk.ts (1)
  • __internal_EnableOrganizationsPromptProps (1449-1459)
packages/clerk-js/src/ui/lazyModules/providers.tsx (1)
  • LazyEnableOrganizationsPromptProvider (212-227)
packages/clerk-js/src/ui/components/devPrompts/EnableOrganizationsPrompt/index.tsx (1)
  • EnableOrganizationsPrompt (433-439)
packages/clerk-js/src/ui/lazyModules/components.ts (1)
  • EnableOrganizationsPrompt (49-51)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (30)
  • GitHub Check: Integration Tests (expo-web, chrome)
  • GitHub Check: Integration Tests (nextjs, chrome, 15, RQ)
  • GitHub Check: Integration Tests (machine, chrome)
  • GitHub Check: Integration Tests (quickstart, chrome, 15)
  • GitHub Check: Integration Tests (ap-flows, chrome)
  • GitHub Check: Integration Tests (nuxt, chrome)
  • GitHub Check: Integration Tests (quickstart, chrome, 16)
  • GitHub Check: Integration Tests (custom, chrome)
  • GitHub Check: Integration Tests (billing, chrome, RQ)
  • GitHub Check: Integration Tests (handshake, chrome)
  • GitHub Check: Integration Tests (nextjs, chrome, 16)
  • GitHub Check: Integration Tests (billing, chrome)
  • GitHub Check: Integration Tests (tanstack-react-start, chrome)
  • GitHub Check: Integration Tests (handshake:staging, chrome)
  • GitHub Check: Integration Tests (sessions:staging, chrome)
  • GitHub Check: Integration Tests (nextjs, chrome, 15)
  • GitHub Check: Integration Tests (react-router, chrome)
  • GitHub Check: Integration Tests (nextjs, chrome, 14)
  • GitHub Check: Integration Tests (sessions, chrome)
  • GitHub Check: Integration Tests (vue, chrome)
  • GitHub Check: Integration Tests (astro, chrome)
  • GitHub Check: Integration Tests (localhost, chrome)
  • GitHub Check: Integration Tests (elements, chrome)
  • GitHub Check: Integration Tests (express, chrome)
  • GitHub Check: Integration Tests (generic, chrome)
  • GitHub Check: Unit Tests (22, **)
  • GitHub Check: Publish with pkg-pr-new
  • GitHub Check: Unit Tests (22, shared, clerk-js, RQ)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (23)
packages/shared/src/react/hooks/useOrganization.tsx (1)

1-1: LGTM: Import addition is correct.

The import of useAttemptToEnableOrganizations is properly added alongside the existing getCurrentOrganizationMembership import.

packages/shared/src/react/__tests__/commerce.test.tsx (1)

56-64: Vitest partial mock of ../contexts looks correct

Using vi.importActual and overriding only useOrganizationContext is a good way to force organization: null while preserving other exports; this keeps the test aligned with the new context-based API without affecting unrelated behavior.

packages/shared/src/types/index.ts (1)

15-15: Re‑exporting devtools types is consistent with existing barrel pattern

The additional export type * from './devtools'; cleanly exposes the new devtools types alongside the rest of the public surface.

packages/clerk-js/src/ui/elements/Modal.tsx (1)

14-24: Forwarding initialFocusRef to Popover is a solid accessibility improvement

Threading initialFocusRef through ModalProps and into Popover.initialFocus lets callers control initial focus without changing existing behavior; the types line up with the common number | ref pattern.

Also applies to: 26-36, 55-63

packages/clerk-js/src/core/clerk.ts (1)

871-885: Centralized enablement flow for organization components looks coherent

Routing all organization-related open/mount entrypoints through __internal_attemptToEnableEnvironmentSetting and short‑circuiting on status === 'prompt-shown' gives a single dev‑only gate for disabled organizations, while preserving non‑dev behavior. The per‑caller onClose callbacks that throw a targeted ClerkRuntimeError in dev also match existing error‑code patterns.

Also applies to: 908-922, 1057-1071, 1104-1118, 1142-1156, 1188-1202, 1393-1403

packages/react/src/isomorphicClerk.ts (1)

121-138: Premount/open behavior for EnableOrganizationsPrompt is consistent with other modals

Storing props in preopenEnableOrganizationsPrompt when ClerkJS isn’t loaded yet, replaying them in hydrateClerkJS, and clearing them in __internal_closeEnableOrganizationsPrompt mirrors the existing preopen patterns (SignIn, Checkout, etc.). The truthy check in hydration is fine since the field is initialized to null and only ever set to an object or null.

Also applies to: 563-567, 587-629, 631-633, 876-890

packages/clerk-js/src/ui/components/APIKeys/APIKeys.tsx (1)

2-7: Switching to useOrganizationContext is a good way to sidestep the dev prompt for API keys

Deriving subject from useOrganizationContext().organization?.id and falling back to user.id keeps the API keys flow working for both org and user subjects without invoking the new enable‑organizations dev prompt via useOrganization. Given the withCoreUserGuard wrapper, the user fallback is safe, and the comment makes the intent clear.

Also applies to: 241-248

packages/clerk-js/bundlewatch.config.json (1)

4-7: Bundle size budget updates look reasonable for the new prompt chunk

The slight increases to the main browser bundle thresholds and the dedicated 6.5KB budget for enableOrganizationsPrompt*.js are consistent with introducing a small lazy‑loaded dev prompt. Nothing here looks out of line.

Also applies to: 26-27

packages/clerk-js/src/ui/customizables/parseAppearance.ts (1)

30-30: LGTM! Appearance key extension follows existing patterns.

The addition of 'enableOrganizationsPrompt' to the appearanceKey union is consistent with the existing 'impersonationFab' pattern and properly integrates with the broader appearance cascade system.

packages/shared/src/types/appearance.ts (2)

1038-1038: LGTM! Type alias follows established conventions.

The EnableOrganizationsTheme type alias is consistent with other theme type definitions in this file (e.g., SignInTheme, UserProfileTheme).


1127-1130: LGTM! Appearance field properly documented.

The enableOrganizations field addition follows the same pattern as other component-specific appearance overrides, with clear JSDoc documentation.

packages/clerk-js/src/ui/lazyModules/components.ts (2)

20-20: LGTM! Import path update reflects directory restructure.

The updated path for KeylessPrompt aligns with the new devPrompts directory structure, improving organization of development-mode prompt components.


30-31: LGTM! EnableOrganizationsPrompt lazy loading follows established patterns.

The integration of EnableOrganizationsPrompt into the lazy loading system is consistent with other components:

  • Import path with webpack chunk name annotation
  • Lazy export extracting the default module export
  • Inclusion in the ClerkComponents registry

Also applies to: 49-51, 153-153

packages/clerk-js/src/ui/components/devPrompts/KeylessPrompt/index.tsx (2)

8-17: LGTM! Centralized shared utilities improve maintainability.

The refactoring to import common prompt primitives (PromptContainer, basePromptElementStyles, PromptSuccessIcon, handleDashboardUrlParsing) from the shared module reduces code duplication and ensures consistency across dev prompts.


116-116: LGTM! Component replacement maintains functionality.

The replacement of custom implementations with shared components (PromptContainer and PromptSuccessIcon) maintains the same visual appearance and behavior while promoting code reuse.

Also applies to: 168-173

packages/clerk-js/src/ui/lazyModules/providers.tsx (1)

212-227: LGTM! Provider follows established patterns.

The LazyEnableOrganizationsPromptProvider mirrors the structure of LazyImpersonationFabProvider, correctly wrapping children with:

  • Suspense boundary for lazy loading
  • VirtualRouter for routing context
  • AppearanceProvider with the correct appearance key
packages/clerk-js/src/ui/components/devPrompts/EnableOrganizationsPrompt/index.tsx (2)

76-82: LGTM! Conditional parameter inclusion prevents errors on older instances.

The logic correctly builds the payload object and only includes organization_allow_personal_accounts when the environment supports it (i.e., when hasPersonalAccountsEnabled is true). This prevents backend errors on older instances that don't support this parameter.


527-656: LGTM! Switch component is well-implemented with good accessibility.

The custom Switch component includes:

  • Proper ARIA roles (role="switch")
  • Keyboard accessibility (no tabIndex={-1})
  • Focus-visible styles via the parent label selector
  • Controlled and uncontrolled modes
  • Associated description with aria-describedby
  • Reduced motion support
packages/clerk-js/src/ui/Components.tsx (5)

3-3: LGTM! Imports properly integrate the new prompt infrastructure.

The imports correctly bring in:

  • Type definitions (__internal_EnableOrganizationsPromptProps)
  • Lazy component (EnableOrganizationsPrompt)
  • Provider wrapper (LazyEnableOrganizationsPromptProvider)

Also applies to: 31-31, 45-45


76-99: LGTM! Type signatures and state properly extended.

The changes correctly:

  • Extend openModal and closeModal type signatures to include 'enableOrganizationsPrompt'
  • Add proper type discrimination for props based on modal type
  • Initialize the state field enableOrganizationsPromptModal

Also applies to: 101-112, 162-162, 256-256


354-367: LGTM! Deduplication logic prevents multiple prompt instances.

The special handling for enableOrganizationsPrompt correctly prevents reopening the prompt if it's already open. This is appropriate given that multiple components/hooks on the same page might trigger the prompt, and showing multiple instances would confuse users. Based on learnings.


639-643: LGTM! Rendering follows established component patterns.

The conditional rendering of EnableOrganizationsPrompt wrapped in LazyEnableOrganizationsPromptProvider is consistent with how other prompts (like ImpersonationFab) are rendered.


337-340: LGTM! Template literal property access fix is appropriate.

The explicit type assertion on line 340 is necessary because TypeScript doesn't narrow types correctly when using template literal property access combined with the in operator. The comment clearly explains the limitation, and the cast is safe given the preceding type guard.

@LauraBeatris LauraBeatris changed the title feat(clerk-js,clerk-react): Introduce development modal to enable organizations feat(clerk-js,clerk-react,vue): Introduce development modal to enable organizations Nov 21, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
packages/clerk-js/src/ui/components/devPrompts/EnableOrganizationsPrompt/index.tsx (2)

73-93: Consider surfacing a lightweight error state when enabling fails

Right now the catch path only clears isLoading. From the user’s perspective the button just re‑enables with no indication whether the attempt failed or silently did nothing, which can be confusing even in a dev‑only UI.

Consider adding a small error state (e.g. const [error, setError] = useState<string | null>(null)) that you clear on start, set in the catch block, and render as a short inline message under the description text.

Also applies to: 292-298


537-560: Add hover and focus-visible styles to Link for better affordance

The Link component currently renders as styled text with no hover or focus-visible feedback. For a primary navigation/action affordance (“dashboard”, “Learn more”), it’s helpful for both pointer and keyboard users to get a visible state change.

You can extend the existing styles along these lines:

 const Link = forwardRef<HTMLAnchorElement, React.ComponentProps<'a'> & { css?: SerializedStyles }>(
   ({ children, css: cssProp, ...props }, ref) => {
     return (
       <a
         ref={ref}
         {...props}
         css={[
           basePromptElementStyles,
           css`
             color: #a8a8ff;
             font-size: inherit;
             font-weight: 500;
             line-height: 1.3;
             font-size: 0.8125rem;
             min-width: 0;
+            cursor: pointer;
+            transition: color 120ms ease-in-out;
+
+            &:hover {
+              color: #c4c4ff;
+            }
+
+            &:focus-visible {
+              outline: 2px solid white;
+              outline-offset: 2px;
+              border-radius: 2px;
+            }
+
+            @media (prefers-reduced-motion: reduce) {
+              transition: none;
+            }
           `,
           cssProp,
         ]}
       >
         {children}
       </a>
     );
   },
 );
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 6b01217 and 17978b5.

📒 Files selected for processing (1)
  • packages/clerk-js/src/ui/components/devPrompts/EnableOrganizationsPrompt/index.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/clerk-js/src/ui/components/devPrompts/EnableOrganizationsPrompt/index.tsx (5)
packages/shared/src/types/clerk.ts (1)
  • __internal_EnableOrganizationsPromptProps (1449-1459)
packages/clerk-js/src/ui/components/devPrompts/shared.tsx (5)
  • handleDashboardUrlParsing (84-100)
  • PromptContainer (10-28)
  • basePromptElementStyles (33-55)
  • ClerkLogoIcon (105-176)
  • PromptSuccessIcon (57-82)
packages/shared/src/types/devtools.ts (1)
  • EnableEnvironmentSettingParams (3-6)
packages/clerk-js/src/core/resources/DevTools.ts (1)
  • DevTools (8-21)
packages/clerk-js/src/ui/elements/Modal.tsx (1)
  • Modal (26-111)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (31)
  • GitHub Check: Integration Tests (nextjs, chrome, 16)
  • GitHub Check: Integration Tests (nextjs, chrome, 15)
  • GitHub Check: Integration Tests (quickstart, chrome, 15)
  • GitHub Check: Integration Tests (billing, chrome)
  • GitHub Check: Integration Tests (quickstart, chrome, 16)
  • GitHub Check: Integration Tests (nextjs, chrome, 15, RQ)
  • GitHub Check: Integration Tests (react-router, chrome)
  • GitHub Check: Integration Tests (machine, chrome)
  • GitHub Check: Integration Tests (billing, chrome, RQ)
  • GitHub Check: Integration Tests (custom, chrome)
  • GitHub Check: Integration Tests (expo-web, chrome)
  • GitHub Check: Integration Tests (nextjs, chrome, 14)
  • GitHub Check: Integration Tests (nuxt, chrome)
  • GitHub Check: Integration Tests (express, chrome)
  • GitHub Check: Integration Tests (vue, chrome)
  • GitHub Check: Integration Tests (astro, chrome)
  • GitHub Check: Integration Tests (tanstack-react-start, chrome)
  • GitHub Check: Integration Tests (sessions:staging, chrome)
  • GitHub Check: Integration Tests (handshake, chrome)
  • GitHub Check: Integration Tests (handshake:staging, chrome)
  • GitHub Check: Integration Tests (localhost, chrome)
  • GitHub Check: Integration Tests (generic, chrome)
  • GitHub Check: Integration Tests (sessions, chrome)
  • GitHub Check: Integration Tests (elements, chrome)
  • GitHub Check: Integration Tests (ap-flows, chrome)
  • GitHub Check: Static analysis
  • GitHub Check: Publish with pkg-pr-new
  • GitHub Check: Unit Tests (22, **)
  • GitHub Check: Unit Tests (22, shared, clerk-js, RQ)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (2)
packages/clerk-js/src/ui/components/devPrompts/EnableOrganizationsPrompt/index.tsx (2)

50-53: Good handling of personal‑account support across instance versions

The hasPersonalAccountsEnabled guard plus conditional inclusion of organization_allow_personal_accounts in EnableEnvironmentSettingParams is a clean way to keep older instances from receiving unsupported flags while still wiring the toggle when the feature is present. This should address the dev_tools compatibility concern without complicating the call‑site.

Also applies to: 76-82


416-463: Switch implementation looks solid from an accessibility standpoint

Nice job on the custom switch:

  • Hidden native <input type="checkbox" role="switch"> with aria-describedby ties semantics to the label/description.
  • Label wrapping, :has(input:focus-visible) for focus ring, and disabled styling via :has(input:disabled) give good keyboard and pointer behavior.
  • Controlled/uncontrolled handling via checked/defaultChecked is straightforward.

No changes requested here.

Also applies to: 465-531

@LauraBeatris
Copy link
Member Author

LauraBeatris commented Nov 21, 2025

I'll make some tests with a Vite app using the mount org methods directly to see how the prompt is getting mounted

Edit: Working just fine! Rendering orgswitcher with Clerk.mountOrganizationSwitcher

CleanShot 2025-11-21 at 16 43 16

@LauraBeatris
Copy link
Member Author

LauraBeatris commented Nov 21, 2025

I'll block release until Monday so we can deploy clerk-js safely

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants